package com.netease.nimlib.ipc.cp.client;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;

import com.netease.nimlib.ipc.cp.protocol.Protocol;

import java.util.HashMap;
import java.util.Map;

/**
 * 进程间数据同步客户端
 * uri=content://{authority}/{type}/{key}/{name}
 * <p>
 * Created by huangjun on 2017/10/31.
 **/

public final class ProviderClient {

    /**
     * ******************************* 对外枚举 ******************************
     */
    public enum UriTypeEnum {
        String(Protocol.URI_TYPE_STRING),
        Boolean(Protocol.URI_TYPE_BOOLEAN),
        Int(Protocol.URI_TYPE_INT),
        Long(Protocol.URI_TYPE_LONG),
        Float(Protocol.URI_TYPE_FLOAT);

        private int val;

        UriTypeEnum(int val) {
            this.val = val;
        }

        public int getInt() {
            return val;
        }
    }

    /**
     * ******************************* 对外接口 ******************************
     */

    private static Map<String, ProviderClient> sClients = new HashMap<>();

    public static synchronized ProviderClient get(Context context, final String name) {
        if (!sClients.containsKey(name)) {
            sClients.put(name, new ProviderClient(context, name));
        }

        return sClients.get(name);
    }

    /**
     * ******************************* 类构造/属性 ******************************
     */

    private Context context;
    private String name;

    private ProviderClient(Context context, String name) {
        this.context = context;
        this.name = name;
    }

    private Map<IContentObserver, ProviderObserver> observers = new HashMap<>();

    /**
     * ******************************* 查询接口 ******************************
     */

    public String queryString(final String key, final String defaultValue) throws Exception {
        Uri URI = Protocol.buildUri(name, key, Protocol.URI_TYPE_STRING);
        String value = defaultValue;
        Cursor cursor = context.getContentResolver().query(URI, null, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            value = cursor.getString(cursor.getColumnIndex(Protocol.URI_VALUE));
        }
        closeCursor(cursor);
        return value;
    }


    public boolean queryBoolean(final String key, final boolean defaultValue) {
        Uri URI = Protocol.buildUri(name, key, Protocol.URI_TYPE_BOOLEAN);
        int value = defaultValue ? 1 : 0;
        Cursor cursor = context.getContentResolver().query(URI, null, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            value = cursor.getInt(cursor.getColumnIndex(Protocol.URI_VALUE));
        }
        closeCursor(cursor);
        return value == 1;
    }


    public int queryInt(final String key, final int defaultValue) {
        Uri URI = Protocol.buildUri(name, key, Protocol.URI_TYPE_INT);
        int value = defaultValue;
        Cursor cursor = context.getContentResolver().query(URI, null, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            value = cursor.getInt(cursor.getColumnIndex(Protocol.URI_VALUE));
        }
        closeCursor(cursor);
        return value;
    }

    public long queryLong(final String key, final long defaultValue) {
        Uri URI = Protocol.buildUri(name, key, Protocol.URI_TYPE_LONG);
        long value = defaultValue;
        Cursor cursor = context.getContentResolver().query(URI, null, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            value = cursor.getLong(cursor.getColumnIndex(Protocol.URI_VALUE));
        }
        closeCursor(cursor);
        return value;
    }

    public float queryFloat(final String key, final float defaultValue) {
        Uri URI = Protocol.buildUri(name, key, Protocol.URI_TYPE_FLOAT);
        float value = defaultValue;
        Cursor cursor = context.getContentResolver().query(URI, null, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            value = cursor.getFloat(cursor.getColumnIndex(Protocol.URI_VALUE));
        }
        closeCursor(cursor);
        return value;
    }

    private static void closeCursor(Cursor cursor) {
        if (cursor != null && !cursor.isClosed()) {
            cursor.close();
        }
    }

    /**
     * ******************************* 更新接口 ******************************
     */

    public void updateString(final String key, final String value, final boolean notify) {
        Uri URI = Protocol.buildUri(name, key, Protocol.URI_TYPE_STRING);
        ContentValues cv = new ContentValues();
        cv.put(Protocol.URI_KEY, key);
        cv.put(Protocol.URI_VALUE, value);
        cv.put(Protocol.URI_NOTIFY, notify);
        context.getContentResolver().update(URI, cv, null, null);
    }

    public void updateBoolean(final String key, final boolean value, final boolean notify) {
        Uri URI = Protocol.buildUri(name, key, Protocol.URI_TYPE_BOOLEAN);
        ContentValues cv = new ContentValues();
        cv.put(Protocol.URI_KEY, key);
        cv.put(Protocol.URI_VALUE, value);
        cv.put(Protocol.URI_NOTIFY, notify);
        context.getContentResolver().update(URI, cv, null, null);
    }

    public void updateInt(final String key, final int value, final boolean notify) {
        Uri URI = Protocol.buildUri(name, key, Protocol.URI_TYPE_INT);
        ContentValues cv = new ContentValues();
        cv.put(Protocol.URI_KEY, key);
        cv.put(Protocol.URI_VALUE, value);
        cv.put(Protocol.URI_NOTIFY, notify);
        context.getContentResolver().update(URI, cv, null, null);
    }

    public void updateLong(final String key, final long value, final boolean notify) {
        Uri URI = Protocol.buildUri(name, key, Protocol.URI_TYPE_LONG);
        ContentValues cv = new ContentValues();
        cv.put(Protocol.URI_KEY, key);
        cv.put(Protocol.URI_VALUE, value);
        cv.put(Protocol.URI_NOTIFY, notify);
        context.getContentResolver().update(URI, cv, null, null);
    }

    public void updateFloat(final String key, final float value, final boolean notify) {
        Uri URI = Protocol.buildUri(name, key, Protocol.URI_TYPE_FLOAT);
        ContentValues cv = new ContentValues();
        cv.put(Protocol.URI_KEY, key);
        cv.put(Protocol.URI_VALUE, value);
        cv.put(Protocol.URI_NOTIFY, notify);
        context.getContentResolver().update(URI, cv, null, null);
    }

    /**
     * ******************************* 事件接口 ******************************
     */

    public void invoke(final String eventKey, final String eventParams) {
        Uri URI = Protocol.buildUri(name, eventKey, Protocol.URI_TYPE_VOID);
        ContentValues cv = new ContentValues();
        cv.put(Protocol.URI_KEY, eventKey);
        cv.put(Protocol.URI_VALUE, eventParams);
        context.getContentResolver().update(URI, cv, null, null);
    }

    /**
     * ******************************* 删除接口 ******************************
     */

    public void removeKey(final String key) {
        Uri URI = Protocol.buildUri(name, key, Protocol.URI_TYPE_STRING);
        context.getContentResolver().delete(URI, null, null);
    }

    /**
     * ******************************* 观察者接口 ******************************
     */

    public void registerObserver(final String key, final UriTypeEnum type, IContentObserver observer) {
        ProviderObserver providerObserver = new ProviderObserver(context, name, key, type.val, observer);
        Uri uri = Protocol.buildUri(name, key, type.val);

        observers.put(observer, providerObserver);
        context.getContentResolver().registerContentObserver(uri, false, providerObserver);
    }

    public void unregisterObserver(IContentObserver observer) {
        if (observer == null) {
            return;
        }

        ProviderObserver providerObserver = observers.get(observer);
        if (providerObserver != null) {
            context.getContentResolver().unregisterContentObserver(providerObserver);
            observers.remove(observer);
        }
    }
}
